package khleuven.mondzorg.db.googlespreadsheet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.util.HashMap;

import khleuven.mondzorg.Logger;
import khleuven.mondzorg.R;
import khleuven.mondzorg.db.DBException;
import khleuven.mondzorg.db.Datasource;
import khleuven.mondzorg.db.readers.EntryBuilder;
import khleuven.mondzorg.domain.BlobLib;
import khleuven.mondzorg.domain.DomainException;
import khleuven.mondzorg.domain.EntryType;
import khleuven.mondzorg.domain.Illustration;
import khleuven.mondzorg.domain.JsonKeysDictionary;
import khleuven.mondzorg.domain.MondAppEntry;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;

public class GoogleSpreadSheet implements Datasource {
	
	// Base url public/values otherwise no JSON!
	// Stiekem heeft public values dan ook geen authenticatie nodig...
	
	//  @see file:///H:/Onderzoek/Mondapp/MondZorgDB/Google2Db/sheets.xml
	// https://spreadsheets.google.com/feeds/worksheets/1wagJm9R7aChRnd4KE2RHfiYRpuw-iIbxonwQKM9D4GE/private/full
	private HashMap<EntryType, String> entry_urls;
	private HashMap<String, String> illustration_url;	
	private HttpClient httpclient;	
	private EntryBuilder eb;
	
	private Context applicationContext; // needed for logging information
	
	public static final boolean onlyPublished = false;
	
	public GoogleSpreadSheet(EntryBuilder eb, Context appContext) throws DBException  
	{
		httpclient = new DefaultHttpClient();
		
		// Example url: https://spreadsheets.google.com/feeds/list/1wagJm9R7aChRnd4KE2RHfiYRpuw-iIbxonwQKM9D4GE/o7d1lby/public/values
		entry_urls = new HashMap<EntryType, String>();
		entry_urls.put(EntryType.DEFINITION, "o7d1lby");
		entry_urls.put(EntryType.FAQ, "oq2h20l");
		entry_urls.put(EntryType.LEARN, "o91nqt1");
		entry_urls.put(EntryType.TEST, "onkqpi3");
		
		illustration_url = new HashMap<String, String>();
		illustration_url.put("ILLUSTRATION", "oqp9fcn");
		
		setEntryBuilder(eb);
		setApplicationContext(appContext);
		
		// Modules: https://spreadsheets.google.com/feeds/worksheets/1wagJm9R7aChRnd4KE2RHfiYRpuw-iIbxonwQKM9D4GE/public/full/o366nna
	}
	
	private void setEntryBuilder(EntryBuilder eb) throws DBException{
		if(eb == null){
			throw new DBException("EB null");
		}
		this.eb = eb;
	}
	private void setApplicationContext(Context appContext) throws DBException{
		if(appContext == null){ throw new DBException("appContext null");}
		else { this.applicationContext = appContext; }
	}
	
	@Override
	public void reloadAllEntriesFromSource() throws DBException {
		createEntryFromGoogleSheet(EntryType.DEFINITION, EntryType.DEFINITION.getConstructor());
		createEntryFromGoogleSheet(EntryType.FAQ, EntryType.FAQ.getConstructor());
		createEntryFromGoogleSheet(EntryType.LEARN, EntryType.LEARN.getConstructor());
		createEntryFromGoogleSheet(EntryType.TEST, EntryType.TEST.getConstructor());
	}
	
	@Override
	public void reloadAllIllustrationsFromSource() throws DBException {
		JSONArray all_illustrations = getJSONEntryArrayResponse(illustration_url.get("ILLUSTRATION"), null);
		Logger.logAsUserLoadingFeedback(applicationContext, R.id.start_retrieving_illustrations, "Retrieving "+all_illustrations.length()+" illustrations from online source");
		
		long start_time_needed_to_retrieve_illustrations = System.currentTimeMillis();
		JSONObject original_json;
		
		for(int i=0; i < all_illustrations.length(); i++) {
			try {
				original_json = all_illustrations.getJSONObject(i);
				eb.add(new Illustration(original_json, BlobLib.getIllustrationBlob(original_json.getJSONObject(JsonKeysDictionary.JSON_KEY_ILL_LINK).getString("$t"))));
			} catch (JSONException e) {
				throw new RuntimeException(e); // should not occur - TODO ignore error for this entry?
			} catch (DomainException e) {
				throw new DBException("Cannot add illustration",e);
			}
		}
		Logger.logDB("Time wasted on retrieving illustration : "+(System.currentTimeMillis()-start_time_needed_to_retrieve_illustrations));		
	}	
	
	private void createEntryFromGoogleSheet(EntryType entry_type, Constructor<? extends MondAppEntry> entryConstructor) throws DBException {
		Logger.logAsUserLoadingFeedback(R.id.start_retrieving_data_information, "Retrieving text information "+entry_type.toString()+" from online source");
		
		long start_time_needed_to_retrieve_entrytype = System.currentTimeMillis();
		String query_id = "sq";
		String query = "";
		if(onlyPublished){
			query = JsonKeysDictionary.JSON_KEY_REVIEW + "=1";
		} else{
			query = JsonKeysDictionary.JSON_KEY_REVIEW + "<>1";
		}

		
		NameValuePair[] params = {
				new GoogleNameValuePair(query_id, query),
				new GoogleNameValuePair("alt", AuthenticationDictionary.data_protocol)
		};

		JSONArray all_def = getJSONEntryArrayResponse(entry_urls.get(entry_type), params);
		eb.createEntriesFromJSonArray(all_def, entry_type, entryConstructor);
		Logger.logDB("Time wasted on retrieving "+entry_type.name()+": "+(System.currentTimeMillis()-start_time_needed_to_retrieve_entrytype));		
		
	}
	

	private JSONArray getJSONEntryArrayResponse(String sheet_id, NameValuePair[] params) throws DBException {
		String sheet_content_xml = 
				"https://spreadsheets.google.com/feeds/list/"+
						AuthenticationDictionary.spreadsheet_id+"/"+sheet_id+"/public/values";
		
		if(params == null) {
			params = new NameValuePair[1];
			params[0] = new GoogleNameValuePair("alt", AuthenticationDictionary.data_protocol);
		}
		
		HttpGet request = new HttpGet(sheet_content_xml+"?"+GoogleNameValuePair.toURLparams(params));
		
		String entries = getResponse(httpclient, request);
		JSONObject entries_json;
		try {
			entries_json = new JSONObject(entries);
		} catch (JSONException e) {
			throw new RuntimeException(e); // should not happen
		}
		
		JSONArray all_def;
		try {
			all_def = entries_json.getJSONObject(
					JsonKeysDictionary.JSON_KEY_GS_FEED).
					getJSONArray(JsonKeysDictionary.JSON_KEY_GS_ENTRY);
		} catch (JSONException e) {
			throw new RuntimeException(e); // should not happen
		}
		
		return all_def;
	}


	private String getResponse(HttpClient httpclient, HttpUriRequest httppost) throws DBException {
		HttpResponse response;
		try {
			response = httpclient.execute(httppost);
		} catch (ClientProtocolException e) {
			throw new DBException(e);
		} catch (IOException e) {
			Logger.logAsUserLoadingFeedback(R.id.error_internet_connection, "Retrieving "+all_illustrations.length()+" illustrations from online source");
			
			throw new DBException(e);
		}
		
		HttpEntity entity = response.getEntity();
		
		// TODO check url not found error, ...
		Header encoding = entity.getContentEncoding();
		if(encoding != null && !encoding.getValue().equalsIgnoreCase(JsonKeysDictionary.PREFERRED_ENCODING)) {
			throw new DBException("Prefered encoding "+JsonKeysDictionary.PREFERRED_ENCODING+" to communicated with GoogleSpreadsheet is not available");
		}
		
		InputStream is = null;
		try {
			is = entity.getContent();
		} catch (IllegalStateException e) {
			throw new RuntimeException(e); // should not occur.
		} catch (IOException e) {
			throw new DBException(e); // should almost never occur..
		}
		
		BufferedReader reader;
		try {
			reader = new BufferedReader(new InputStreamReader(is,JsonKeysDictionary.PREFERRED_ENCODING));
		} catch (UnsupportedEncodingException e) {
			throw new DBException("Prefered encoding "+JsonKeysDictionary.PREFERRED_ENCODING+" to communicated with GoogleSpreadsheet is not available");
		}
		
		StringBuilder sb = new StringBuilder();
		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line + " ");
			}
			reader.close();
		} catch (IOException e) {
			// stop reading the input file.. ignore the error.
		}
		
		try {
			is.close();
		} catch (IOException e) {
			// stop closing the input file.. ignore the error.
		}
		
		String result=sb.toString();
		return result;
	}
	

}

